package cn.ibizlab.util.filter;


import com.alibaba.fastjson.annotation.JSONField;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.data.annotation.Transient;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
@JsonInclude(JsonInclude.Include.NON_NULL)
public class SearchCondition {

    /**
     * 条件类型
     */
    @JsonProperty("condtype")
    @JSONField(name = "condtype")
    private String condType;

    /**
     * 名称
     */
    @JsonProperty("name")
    @JSONField(name = "name")
    private String name;

    /**
     * 属性名称
     */
    @JsonProperty("fieldname")
    @JSONField(name = "fieldname")
    private String fieldname;

    /**
     * 获取条件操作，值参考 net.ibizsys.runtime.util.Conditions
     */
    @JsonProperty("condop")
    @JSONField(name = "condop")
    private String condOp;

    /**
     * 条件值
     */
    @JsonProperty("value")
    @JSONField(name = "value")
    private Object value;

    /**
     * 指定值是否来自参数
     */
    @JsonProperty("parammode")
    @JSONField(name = "parammode")
    private boolean paramMode;

    /**
     * 数据类型
     */
    @JsonProperty("datatype")
    @JSONField(name = "datatype")
    private int dataType;

    /**
     * 值函数
     */
    @JsonProperty("valuefunc")
    @JSONField(name = "valuefunc")
    private String valueFunc;

    /**
     * 选项
     */
    @JsonProperty("option")
    @JSONField(name = "option")
    private String option;

    /**
     * 获取查询过滤对象集合
     */
    @JsonProperty("searchconds")
    @JSONField(name = "searchconds")
    private List<SearchCondition> searchConds;

    /**
     * 是否为逻辑取反模式
     */
    @JsonProperty("notmode")
    @JSONField(name = "notmode")
    private boolean notMode;

    /**
     * 获取分组条件的分类 分类用于标记分组条件的用途
     */
    @JsonProperty("cat")
    @JSONField(name = "cat")
    private String cat;

    /**
     * 自定义条件
     */
    @JsonProperty("customcond")
    @JSONField(name = "customcond")
    private String customCond;

    /**
     * 条件标记
     */
    @JsonProperty("tag")
    @JSONField(name = "tag")
    private String tag;

    /**
     * 预定义条件
     */
    @JsonProperty("predefinedcode")
    @JSONField(name = "predefinedcode")
    private String predefinedCode;

    /**
     * 预定义类型
     */
    @JsonProperty("predefinedtype")
    @JSONField(name = "predefinedtype")
    private String predefinedType;

    public synchronized SearchCondition addCondition(String field,String op,Object value) {
        if (searchConds == null)
            searchConds = new ArrayList<>();
        searchConds.add(new SearchCondition().setFieldname(field).setCondType(Conditions.CONDTYPE_DEFIELD).setValue(value).setCondOp(op.toUpperCase()));
        return this;
    }


    @JsonIgnore
    @JSONField(serialize = false)
    @Transient
    private QueryFilter filter;

    @JsonIgnore
    @JSONField(serialize = false)
    public QueryFilter getFilter() {
        if(filter == null)
            filter = getCondition(this);
        return filter;
    }

    /**
     * 添加自定义条件
     * @param searchCondition
     * @return
     */
    protected QueryFilter getCondition(SearchCondition searchCondition){
        QueryFilter cond = null;
        String condType = searchCondition.getCondType();
        if(org.springframework.util.StringUtils.hasLength(condType)){
            switch (condType){
                case Conditions.CONDTYPE_DEFIELD:
                    cond = this.getFieldCondition(searchCondition);
                    break;
                case Conditions.CONDTYPE_GROUP:
                    cond = this.getGroupCondition(searchCondition);
                    break;
                case Conditions.CONDTYPE_ITEMS:
                    String fieldName = searchCondition.getFieldname();
                    List<SearchCondition> items = searchCondition.getSearchConds();
                    if(org.springframework.util.StringUtils.hasLength(fieldName) && items.size() > 0){
                        List<QueryFilter> condItems = new ArrayList<>();
                        for(SearchCondition item : items){
                            QueryFilter condItem = this.getCondition(item);
                            if(condItem != null){
                                condItems.add(condItem);
                            }
                        }
                        if(condItems.size() > 0){
                            cond = QueryFilter.createQuery().and(condItems);
                        }
                    }
                    break;
            }
        }
        return cond;
    }

    /**
     * 处理分组条件
     * @param group
     * @return
     */
    protected QueryFilter getGroupCondition(SearchCondition group){
        QueryFilter groupCond = QueryFilter.createQuery();
        List<SearchCondition> children = group.getSearchConds();
        if(children != null && children.size() > 0){
            List<QueryFilter> condition = new ArrayList<>();
            for(SearchCondition child : children){
                QueryFilter cond = this.getCondition(child);
                if(cond != null){
                    condition.add(cond);
                }
            }
            if(condition.size() > 0){
                switch (group.getCondOp()){
                    case Conditions.AND:
                        groupCond.and(condition);
                        break;
                    case Conditions.OR:
                        groupCond.or(condition);
                        break;
                }
            }
        }
        return groupCond;
    }

    /**
     * 处理字段条件
     * @param field
     * @return
     */
    protected QueryFilter getFieldCondition(SearchCondition field){
        QueryFilter fieldCond = QueryFilter.createQuery();
        String column = field.getFieldname();
        Object val = field.getValue();
        if (field.paramMode && val instanceof String)
            val="$."+val;
        switch (field.getCondOp()) {
            // 等于
            case Conditions.EQ:
                fieldCond.eq(column,val);
                break;
            // 不等于
            case Conditions.NOTEQ:
                fieldCond.ne(column,val);
                break;
            // 大于
            case Conditions.GT:
                fieldCond.gt(column,val);
                break;
            // 大于等于
            case Conditions.GTANDEQ:
                fieldCond.ge(column,val);
                break;
            // 小于
            case Conditions.LT:
                fieldCond.lt(column,val);
                break;
            // 小于等于
            case Conditions.LTANDEQ:
                fieldCond.le(column,val);
                break;
            // 为空
            case Conditions.ISNULL:
                fieldCond.isnull(column);
                break;
            // 不为空
            case Conditions.ISNOTNULL:
                fieldCond.isnotnull(column);
                break;
            // 文本包含
            case Conditions.LIKE:
            case Conditions.USERLIKE:
                fieldCond.like(column,(String)val);
                break;
            // 值在范围中
            case Conditions.IN:
                fieldCond.in(column,val);
                break;
            // 值不在范围中
            case Conditions.NOTIN:
                fieldCond.notin(column,val);
                break;
            // 文本左包含
            case Conditions.LEFTLIKE:
                fieldCond.startsWith(column,(String)val);
                break;
            // 文本右包含
            case Conditions.RIGHTLIKE:
                fieldCond.endsWith(column,(String)val);
                break;
        }
        return fieldCond;
    }
}